﻿using Examination.Args;
using Examination.Args.Request;
using Examination.Filter;
using Examination.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Examination.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    [TypeFilter(typeof(WebVerificationAdminFilterAttribute))]
    public class PaperController : ControllerBase
    {
        private readonly DataContext _dataContext;

        public PaperController(DataContext dataContext) => _dataContext = dataContext;

        [HttpPost]
        public async Task<IActionResult> AllQuestion()
        {
            var questions = await _dataContext.Questions.Select(q => new { q.Id, q.Title, q.Type }).ToListAsync();
            return new JsonResult(new ResponseData() { Data = questions });
        }

        [HttpPost]
        public async Task<IActionResult> Search([FromBody] ListParameter parameter)
        {
            object papers;
            long[] ids;
            long total = 0;
            if (string.IsNullOrEmpty(parameter.Key))
            {
                var es = await _dataContext.Examinations.Join(_dataContext.Users, e => e.CreatorId, u => u.Id, (e, u) => new { e.Id, e.CreateTime, e.Title, e.RadioCount, e.RadioScore, e.MultipleCount, e.MultipleScore, e.JudgeCount, e.JudgeScore, e.FillCount, e.FillScore, e.StartTime, e.EndTime, e.Time, e.RandomQuestions, e.RandomOptions, e.Times, e.Type, creator = u.Name }).OrderByDescending(e => e.CreateTime).Skip(parameter.Page * parameter.Size).Take(parameter.Size).ToListAsync();
                total = await _dataContext.Examinations.Join(_dataContext.Users, e => e.CreatorId, u => u.Id, (e, u) => e.Id).CountAsync();
                ids = es.Select(p => p.Id).ToArray();
                papers = es;
            }
            else
            {
                var es = await _dataContext.Examinations.Join(_dataContext.Users, e => e.CreatorId, u => u.Id, (e, u) => new { e.Id, e.CreateTime, e.Title, e.RadioCount, e.RadioScore, e.MultipleCount, e.MultipleScore, e.JudgeCount, e.JudgeScore, e.FillCount, e.FillScore, e.StartTime, e.EndTime, e.Time, e.RandomQuestions, e.RandomOptions, e.Times, e.Type, creator = u.Name }).Where(e => e.Title.Contains(parameter.Key) || e.creator.Contains(parameter.Key)).OrderByDescending(e => e.CreateTime).Skip(parameter.Page * parameter.Size).Take(parameter.Size).ToListAsync();
                total = await _dataContext.Examinations.Join(_dataContext.Users, e => e.CreatorId, u => u.Id, (e, u) => new { e.Id, e.Title, creator = u.Name }).CountAsync(e => e.Title.Contains(parameter.Key) || e.creator.Contains(parameter.Key));
                ids = es.Select(p => p.Id).ToArray();
                papers = es;
            }
            long all = await _dataContext.Examinations.CountAsync();
            long start = await _dataContext.Examinations.CountAsync(u => u.StartTime > DateTime.Now);
            long over = await _dataContext.Examinations.CountAsync(u => u.EndTime < DateTime.Now);
            long going = await _dataContext.Examinations.CountAsync(u => u.StartTime <= DateTime.Now && u.EndTime >= DateTime.Now);
            var examQuestions = await _dataContext.ExamQuestions.Where(eq => ids.Contains(eq.ExaminationId)).Select(eq => new { eq.ExaminationId, eq.QuestionId }).ToListAsync();
            var examPapers = await _dataContext.Papers.Where(p => ids.Contains(p.ExaminationId)).Select(p => new {p.ExaminationId, p.UserId}).ToListAsync();
            var userCount = await _dataContext.Users.CountAsync();
            return new JsonResult(new ResponseData() { Data = new { papers, all, start, over, going, examQuestions, examPapers, userCount, total } });
        }

        [HttpPost]
        public async Task<IActionResult> Create([FromBody] CreatePaperParameter parameter, [FromServices] IArgsExtend argsExtend)
        {
            User user = ((ArgsExtend)argsExtend).User;
            if (await _dataContext.Questions.CountAsync(q => parameter.Questions.Contains(q.Id)) != parameter.Questions.Length)
            {
                return new JsonResult(new ResponseData() { Status = 1, Msg = "创建失败，可能是有不存在的题" });
            }
            Model.Examination examination = new Model.Examination()
            {
                CreatorId = user.Id,
                Title = parameter.Title,
                RadioCount = parameter.RadioCount,
                RadioScore = parameter.RadioScore,
                MultipleCount = parameter.MultipleCount,
                MultipleScore = parameter.MultipleScore,
                JudgeCount = parameter.JudgeCount,
                JudgeScore = parameter.JudgeScore,
                FillCount = parameter.FillCount,
                FillScore = parameter.FillScore,
                StartTime = parameter.StartTime,
                EndTime = parameter.EndTime,
                Time = parameter.Time,
                RandomQuestions = parameter.RandomQuestions,
                RandomOptions = parameter.RandomOptions,
                Times = parameter.Times,
                Type = parameter.Type
            };
            await _dataContext.Examinations.AddAsync(examination);
            await _dataContext.SaveChangesAsync();
            for (int i = 0; i < parameter.Questions.Length; i++)
            {
                await _dataContext.ExamQuestions.AddAsync(new ExamQuestion() { ExaminationId = examination.Id, QuestionId = parameter.Questions[i] });
            }
            await _dataContext.SaveChangesAsync();
            return new JsonResult(new ResponseData() { Data = examination });
        }

        [HttpPost]
        public async Task<IActionResult> Update([FromBody] UpdatePaperParameter parameter, [FromServices] IArgsExtend argsExtend)
        {
            User user = ((ArgsExtend)argsExtend).User;
            Model.Examination examination = await _dataContext.Examinations.FirstOrDefaultAsync(e => e.Id == parameter.Id);
            if (examination == null)
            {
                return new JsonResult(new ResponseData() { Status = 1, Msg = "修改失败，比赛不存在" });
            }
            if (await _dataContext.Questions.CountAsync(q => parameter.Questions.Contains(q.Id)) != parameter.Questions.Length)
            {
                return new JsonResult(new ResponseData() { Status = 1, Msg = "修改失败，可能是有不存在的题" });
            }
            if (await _dataContext.Papers.CountAsync(p => p.ExaminationId == examination.Id) > 0)
            {
                return new JsonResult(new ResponseData() { Status = 1, Msg = "修改失败，已有比赛在进行，你可以尝试删除该试卷" });
            }
            examination.CreatorId = user.Id;
            examination.Title = parameter.Title;
            examination.RadioCount = parameter.RadioCount;
            examination.RadioScore = parameter.RadioScore;
            examination.MultipleCount = parameter.MultipleCount;
            examination.MultipleScore = parameter.MultipleScore;
            examination.JudgeCount = parameter.JudgeCount;
            examination.JudgeScore = parameter.JudgeScore;
            examination.FillCount = parameter.FillCount;
            examination.FillScore = parameter.FillScore;
            examination.StartTime = parameter.StartTime;
            examination.EndTime = parameter.EndTime;
            examination.Time = parameter.Time;
            examination.RandomQuestions = parameter.RandomQuestions;
            examination.RandomOptions = parameter.RandomOptions;
            examination.Times = parameter.Times;
            examination.Type = parameter.Type;
            long[] questions = await _dataContext.ExamQuestions.Where(eq => eq.ExaminationId == examination.Id).Select(eq => eq.QuestionId).ToArrayAsync();
            long[] adds = parameter.Questions.Except(questions).ToArray();
            long[] dels = questions.Except(parameter.Questions).ToArray();
            await _dataContext.ExamQuestions.AddRangeAsync(adds.Select(a => new ExamQuestion() { ExaminationId = examination.Id, QuestionId = a }));
            _dataContext.ExamQuestions.RemoveRange(await _dataContext.ExamQuestions.Where(e => e.ExaminationId == examination.Id && dels.Contains(e.QuestionId)).ToListAsync());
            _dataContext.Examinations.Update(examination);
            await _dataContext.SaveChangesAsync();
            return new JsonResult(new ResponseData() { Data = examination });
        }


        [HttpPost]
        public async Task<IActionResult> Delete([FromQuery] int id, [FromServices] IArgsExtend argsExtend)
        {
            User user = ((ArgsExtend)argsExtend).User;
            if (user.Type != UserType.System)
            {
                return new JsonResult(ResponseData.NoPermission());
            }
            long[] ids = _dataContext.Papers.Where(p => p.ExaminationId == id).Select(p => p.Id).ToArray();
            _dataContext.PaperQuestions.RemoveRange(await _dataContext.PaperQuestions.Where(pq => ids.Contains(pq.PaperId)).ToListAsync());
            _dataContext.Papers.RemoveRange(await _dataContext.Papers.Where(p => p.ExaminationId == id).ToListAsync());
            _dataContext.Examinations.RemoveRange(await _dataContext.Examinations.Where(e => e.Id == id).ToListAsync());
            await _dataContext.SaveChangesAsync();
            return new JsonResult(new ResponseData());
        }
    }
}
